#pragma once

#include "mychain.h"
#include <QFont>
#include <QKeyEvent>
#include <QLabel>
#include <QLineEdit>
#include <QList>
#include <QMainWindow>
#include <QPushButton>
#include <QTimer>
#include <QWidget>
#include <ctime>

const int x_max = 40, y_max = 40, label_size = 20; // 背景的尺寸和每个块的大小
const int dFood = 3; // 每吃一个食物增加的长度

class MyQLabel;

//表示一个背景格子
struct Square {
  MyQLabel *label = nullptr;

  //是蛇的身体或者障碍物就设置为false，食物和空格都是true
  bool can_use = true;
  bool is_border = false;

  //判断是不是食物
  bool is_food = false;

  int x;
  int y;
};

// 封装的QLabel类，以完成响应单击，快速回寻方块的功能
class MyQLabel : public QLabel {

  Q_OBJECT

public:
  Square *p = nullptr;
  explicit MyQLabel(QWidget *parent = nullptr) : QLabel(parent) {}
  ~MyQLabel() {}
  void mousePressEvent(QMouseEvent *event) {
    if (event->button() == Qt::LeftButton)
      emit mousePress(p->x, p->y);
  }

signals:
  void mousePress(int x, int y);
};

//表示蛇的一个块，记录了它的位置
class SnakeSquare {
public:
  int x;
  int y;
  SnakeSquare(int xx = 0, int yy = 0) : x(xx), y(yy) {}
};

QT_BEGIN_NAMESPACE
namespace Ui {
//游戏窗口
class SnakeWindow;
} // namespace Ui
QT_END_NAMESPACE

//游戏界面的管理类
class MainWindow : public QMainWindow {

  Q_OBJECT

public:
  explicit MainWindow(QWidget *parent = nullptr);
  ~MainWindow();
  void init();         // 初始化游戏
  void initSnake();    // 初始化蛇
  void initSquares();  // 初始化背景板
  void stop();         // 暂停游戏
  void resume();       // 继续游戏
  void drawBorder();   // 画边界
  void drawViewArea(); // 画显示区域
  void showViewArea(); // 显示分数和等级
  void gameOver();     // 游戏结束，出现弹窗
  void moveSnake();
  void createFood();

  // 本来想设置背景图片的，后来不想写了
  // void setImage();

protected:
  void keyPressEvent(
      QKeyEvent *e); // 这个函数是继承来的，可以重载实现对按键事件作出响应

  // 有的是套娃函数，一开始写的时候忘记放slot里边了
public slots:
  void snakeMoveSlots();    // 移动操作
  void startGameSlots();    // 游戏开始
  void pauseGameSlots();    // 暂停游戏
  void resumeGameSlots();   // 继续游戏
  void loadGameSlots();     // 加载保存好的游戏文件
  void saveGameSlots();     // 把当前游戏的信息保存到某个文件中
  void restartGameSlots();  // 重开游戏
  void setBlocks(int, int); // 用户把一个块设置成障碍物

private:
  Ui::SnakeWindow *ui;

  QTimer timer;

  Square squares[x_max][y_max]; // 储存游戏画面
  mychain<SnakeSquare> snake;   // 蛇的位置

  int dX, dY; // 在两个方向的移动，即表示蛇的方向
  int foodCount =
      0; // 用来指示要不要新增食物。用int是因为以后可以增加多食物的模式
  int foodTotal = 0;        // 场上的食物总数
  int moveSpeed = 400;      // 移动速度（指timer设置的时长）
  int level = 1, score = 0; // 分数和等级
  int dScore = 1;           // 每次加分数
  QLabel *mLabel;           // 显示分数和等级
  QString viewText;         // 显示区域文本
  int foodLeft = 0; // 还有多少个因为食物而延长的格子没加
  int steps = 0;    // 蛇移动了多少格了（用于实时显示）

  bool movable = false; // 指示要不要对按键做出响应，暂停和结束状态设为false
  bool started = false; // 区分是暂停状态还是未开始状态
  bool putable = true; // 指示能不能让用户在点击鼠标的时候增减障碍物

  // 一开始没考虑到会重复展示分数栏的边界，所以就加上这个来标识一下
  // 因为是用new来建立那些label的，所以如果每次都重复操作会造成内存泄漏
  bool flag_for_drawViewArea = true;
};
